<template>
  <span>{{currentValue}}</span>
</template>

<script>
export default {
  name: "MyNumberAnimation",
  props: {
    from: {
      type: Number,
      default: 0,
    },
    to: {
      type: Number,
      required: true,
    },
    autoplay: {
      type: Boolean,
      default: true,
    },
    showSeparator: Boolean,
    duration: {
      type: Number,
      default: 3000,
    },
    precision: {
      type: Number,
      default: 0,
    },
  },
  data() {
    return {
      currentValue: this.from,
      isAnimate: false,
      startTime: null,
      rAF: null,
    };
  },
  computed: {
    isCountDown() {
      return this.from > this.to;
    },
  },
  mounted() {
    this.autoplay && this.start();
  },
  beforeDestroy() {
    if (this.rAF) {
      cancelAnimationFrame(this.rAF);
      this.rAF = null;
    }
  },
  methods: {
    start() {
      if (this.isAnimate) return;
      this.currentValue = this.from;
      this.isAnimate = true;
      this.startTime = Date.now();
      this.rAF = requestAnimationFrame(this.count);
    },
    count() {
      const progress = (Date.now() - this.startTime) / this.duration;
      let value;
      if (this.isCountDown) {
        value = this.from - (this.from - this.to) * this.easeOut(progress);
        value = value < this.to ? this.to : value;
      } else {
        value = this.from + (this.to - this.from) * this.easeOut(progress);
        value = value > this.to ? this.to : value;
      }
      this.currentValue = this.formatNumber(value);
      if (progress < 1) {
        this.rAF = requestAnimationFrame(this.count);
      } else {
        this.isAnimate = false;
        cancelAnimationFrame(this.rAF);
        this.rAF = null;
      }
    },
    easeOut(p) {
      return 1 - Math.pow(1 - p, 5);
    },
    formatNumber(num) {
      // 将num转为Number类型，因为其值可能为字符串数值，调用toFixed会报错
      num = Number(num);
      num = num.toFixed(Number(this.precision));
      num += "";
      const x = num.split(".");
      let x1 = x[0];
      const x2 = x.length > 1 ? "." + x[1] : "";
      const rgx = /(\d+)(\d{3})/;
      if (this.showSeparator) {
        while (rgx.test(x1)) {
          x1 = x1.replace(rgx, "$1,$2");
        }
      }
      return x1 + x2;
    },
  },
};
</script>

<style>
</style>